#include "SDRAM_DDR_device.h"

SDRAM_DDR_device::SDRAM_DDR_device(sc_module_name	name_)
	: sc_module					(name_)
	, ext_bitwidth_component	(DDR_EXT_BITWIDTH_COMPONENT)
	, column_num				(DDR_DEFAULT_COL_NUM)
	, row_num					(DDR_DEFAULT_ROW_NUM)
	, bank_num					(DDR_DEFAULT_BANK_NUM)
	, rank_num					(DDR_DEFAULT_RANK_NUM)
	, tRCD						(DDR_DEFAULT_tRCD)
	, tRP						(DDR_DEFAULT_tRP)
	, tWR						(DDR_DEFAULT_tWR)
	, DQS						('Z')
{
	component_per_rank_num = (rank_num * DDR_EXT_BITWIDTH_MODULE / ext_bitwidth_component) / rank_num;

	generate_cells();
	initialize_cells();

	SDRAM_DDR_mode_register_set(0, 0xA62);
	SDRAM_DDR_mode_register_set(1, 0x0);
	SDRAM_DDR_mode_register_set(2, 0x0);

	SC_THREAD(bank_count_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(command_count_action);
	dont_initialize();
	sensitive << CLK;
}

SDRAM_DDR_device::SDRAM_DDR_device(sc_module_name	name_,
								   SDRAM_bitwidth_t	bitwidth_module_,
								   SDRAM_num_t		rank_num_,
								   SDRAM_size_t		technology_,
								   SDRAM_bitwidth_t	bitwidth_comp_,
								   unsigned			CL_,
								   unsigned			tRCD_,
								   unsigned			tRP_,
								   unsigned			tWR_)
	: sc_module					(name_)
	, ext_bitwidth_component	(bitwidth_comp_)
	, rank_num					(rank_num_)
	, tRCD						(tRCD_)
	, tRP						(tRP_)
	, tWR						(tWR_)
{
	component_per_rank_num = (rank_num * bitwidth_module_ / ext_bitwidth_component) / rank_num;

	determine_nums(technology_, bitwidth_comp_);
	generate_cells();
	initialize_cells();

	SC_THREAD(bank_count_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(command_count_action);
	dont_initialize();
	sensitive << CLK;
}

SDRAM_DDR_device::~SDRAM_DDR_device()
{
	switch(ext_bitwidth_component)
	{
	case 8:
		for (int i=0;i<rank_num;i++)
		{
			for (int j=0;j<component_per_rank_num;j++)
			{
				for (int k=0;k<bank_num;k++)
				{
					for (int l=0;l<row_num;l++)
						delete[] SDRAM_array_byte[i][j][k][l];
					delete[] SDRAM_array_byte[i][j][k];
					delete[] row_buffer_byte[i][j][k];
				}
				delete[] SDRAM_array_byte[i][j];
				delete[] row_buffer_byte[i][j];
			}
			delete[] SDRAM_array_byte[i];
			delete[] row_buffer_byte[i];

			delete[] read_commanded[i];
			delete[] read_commanded_time[i];
			delete[] write_finished[i];
			delete[] write_finished_time[i];
		}
		delete[] SDRAM_array_byte;
		delete[] row_buffer_byte;
		break;
	case 16:
		for (int i=0;i<rank_num;i++)
		{
			for (int j=0;j<component_per_rank_num;j++)
			{
				for (int k=0;k<bank_num;k++)
				{
					for (int l=0;l<row_num;l++)
						delete[] SDRAM_array_halfword[i][j][k][l];
					delete[] SDRAM_array_halfword[i][j][k];
					delete[] row_buffer_halfword[i][j][k];
				}
				delete[] SDRAM_array_halfword[i][j];
				delete[] row_buffer_halfword[i][j];
			}
			delete[] SDRAM_array_halfword[i];
			delete[] row_buffer_halfword[i];

			delete[] read_commanded[i];
			delete[] read_commanded_time[i];
			delete[] write_finished[i];
			delete[] write_finished_time[i];
		}
		delete[] SDRAM_array_halfword;
		delete[] row_buffer_halfword;
		break;
	case 32:
		for (int i=0;i<rank_num;i++)
		{
			for (int j=0;j<component_per_rank_num;j++)
			{
				for (int k=0;k<bank_num;k++)
				{
					for (int l=0;l<row_num;l++)
						delete[] SDRAM_array_word[i][j][k][l];
					delete[] SDRAM_array_word[i][j][k];
					delete[] row_buffer_word[i][j][k];
				}
				delete[] SDRAM_array_word[i][j];
				delete[] row_buffer_word[i][j];
			}
			delete[] SDRAM_array_word[i];
			delete[] row_buffer_word[i];

			delete[] read_commanded[i];
			delete[] read_commanded_time[i];
			delete[] write_finished[i];
			delete[] write_finished_time[i];
		}
		delete[] SDRAM_array_word;
		delete[] row_buffer_word;

		delete[] read_commanded;
		delete[] read_commanded_time;
		delete[] write_finished;
		delete[] write_finished_time;
		break;
	default:
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
		sc_stop();	
	}
}

const bool
SDRAM_DDR_device::SDRAM_DDR_mode_register_set(unsigned			EMRS_num_,
											  unsigned short	EMRS_code_)
{
	switch(EMRS_num_)
	{
	case 0:
		mode_register.active_power_down_slow_exit = (EMRS_code_ >> 12) & 0x1;
		mode_register.write_recovery  = ((EMRS_code_ >> 9) & 0x7) + 1;
		mode_register.DLL_reset  = (EMRS_code_ >> 8) & 0x1;
		mode_register.test_mode  = (EMRS_code_ >> 7) & 0x1;
		mode_register.CAS_latency = (EMRS_code_ >> 4) & 0x7;
		mode_register.burst_type = (EMRS_code_ >> 3) & 0x1;
		mode_register.burst_length = pow(2, EMRS_code_ & 0x7);
		break;
	case 1:
		mode_register.output_buffer_enable = ~((EMRS_code_ >> 12) & 0x1);
		mode_register.RDQS_enable = (EMRS_code_ >> 11) & 0x1;
		mode_register.DQS_bar_enable  = ~((EMRS_code_ >> 10) & 0x1);
		mode_register.OCD_calibration_program  = (EMRS_code_ >> 7) & 0x7;
		mode_register.additive_latency  = (EMRS_code_ >> 3) & 0x7;
		mode_register.ODT_resistance = (EMRS_code_ >> 5) & 0x2 | (EMRS_code_ >> 2) & 0x1;
		mode_register.output_driver_impedance_control = (EMRS_code_ >> 1) & 0x1;
		mode_register.DLL_enable = ~(EMRS_code_ & 0x1);
		break;
	case 2:
		mode_register.high_temperature_self_refresh_rate_enable = (EMRS_code_ >> 7) & 0x1;
		mode_register.partial_array_self_refresh = EMRS_code_ & 0x7;
		break;
	default:
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> Unsupported EMRS command." << endl;
		sc_stop();
		break;
	}

	return true;
}

const bool
SDRAM_DDR_device::SDRAM_refresh(bool	refresh_type_)
{
	return true;
}

const bool
SDRAM_DDR_device::SDRAM_row_activate(unsigned		rank_sel_,
									 unsigned		bank_sel_,
									 SDRAM_addr_t	row_addr_)
{
	if (!bank_state[rank_sel_][bank_sel_].row_active)
	{
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> row activate command accepted from idle bank." << endl;
#endif
		bank_state[rank_sel_][bank_sel_].row_index = row_addr_;
		bank_state[rank_sel_][bank_sel_].row_activate_enable = true;
		bank_state[rank_sel_][bank_sel_].row_activate_enable_time = sc_time_stamp();
		bank_state[rank_sel_][bank_sel_].row_activate_count = tRCD;
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> row activate counter : " << bank_state[rank_sel_][bank_sel_].row_activate_count;
#endif
		bank_state[rank_sel_][bank_sel_].row_activate_count--;
#ifdef	DEBUG_SDRAM_DDR
		cout << " -> " << bank_state[rank_sel_][bank_sel_].row_activate_count << endl;
#endif
	}
	else
	{
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> this row is already activated." << endl;
		sc_stop();
	}

	return true;
}

const bool
SDRAM_DDR_device::SDRAM_read_command(unsigned		rank_sel_,
									 unsigned		bank_sel_,
									 SDRAM_addr_t	col_addr_,
									 bool			auto_precharge_)
{
	if (bank_state[rank_sel_][bank_sel_].row_active)
	{
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> read command accepted from activated bank." << endl;
#endif
		read_commanded[rank_sel_][bank_sel_] = true;
		read_commanded_time[rank_sel_][bank_sel_] = sc_time_stamp();

		bank_state[rank_sel_][bank_sel_].col_index = col_addr_;
		bank_state[rank_sel_][bank_sel_].current_burst = 0;
		bank_state[rank_sel_][bank_sel_].CAS_latency_count = mode_register.CAS_latency;
		bank_state[rank_sel_][bank_sel_].auto_precharge = auto_precharge_;
		for (int i=0;i<component_per_rank_num;i++)
		{
			switch (ext_bitwidth_component)
			{
			case 8:
				output_buffer_byte[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].current_burst] = row_buffer_byte[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+bank_state[rank_sel_][bank_sel_].current_burst];
				break;
			case 16:
				output_buffer_halfword[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].current_burst] = row_buffer_halfword[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+bank_state[rank_sel_][bank_sel_].current_burst];
				break;
			case 32:
				output_buffer_word[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].current_burst] = row_buffer_word[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+bank_state[rank_sel_][bank_sel_].current_burst];
				break;
			default:
				cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
				sc_stop();	
			}
		}
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> current burst : " << bank_state[rank_sel_][bank_sel_].current_burst;
#endif
		bank_state[rank_sel_][bank_sel_].current_burst++;
#ifdef	DEBUG_SDRAM_DDR
		cout << " -> " << bank_state[rank_sel_][bank_sel_].current_burst << endl;
#endif
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> CAS latency : " << bank_state[rank_sel_][bank_sel_].CAS_latency_count;
#endif
		bank_state[rank_sel_][bank_sel_].CAS_latency_count--;
#ifdef	DEBUG_SDRAM_DDR
		cout << " -> " << bank_state[rank_sel_][bank_sel_].CAS_latency_count << endl;
#endif
	}
	else
	{
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> this row is not activated." << endl;
		sc_stop();
	}

	return true;
}

const SDRAM_DDR_data_t
SDRAM_DDR_device::SDRAM_DDR_read_data(unsigned	rank_sel_,
									  unsigned	bank_sel_,
									  unsigned	current_burst_,
									  bool		direct_access_)
{
	SDRAM_DDR_data_t return_data;

	return_data.lower_bytes = 0;
	return_data.upper_bytes = 0;
	for (int i=0;i<component_per_rank_num;i++)
	{
		if (i<component_per_rank_num/2)
		{
			switch (ext_bitwidth_component)
			{
			case 8:
				return_data.lower_bytes |= ((unsigned)output_buffer_byte[rank_sel_][bank_sel_][i][current_burst_]) << i*ext_bitwidth_component;
				break;
			case 16:
				return_data.lower_bytes |= ((unsigned)output_buffer_halfword[rank_sel_][bank_sel_][i][current_burst_]) << i*ext_bitwidth_component;
				break;
			case 32:
				return_data.lower_bytes = output_buffer_word[rank_sel_][bank_sel_][i][current_burst_];
				break;
			default:
				cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
				sc_stop();	
			}
		}
		else
		{
			switch (ext_bitwidth_component)
			{
			case 8:
				return_data.upper_bytes |= ((unsigned)output_buffer_byte[rank_sel_][bank_sel_][i][current_burst_]) << i*ext_bitwidth_component;
				break;
			case 16:
				return_data.upper_bytes |= ((unsigned)output_buffer_halfword[rank_sel_][bank_sel_][i][current_burst_]) << i*ext_bitwidth_component;
				break;
			case 32:
				return_data.upper_bytes = output_buffer_word[rank_sel_][bank_sel_][i][current_burst_];
				break;
			default:
				cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
				sc_stop();	
			}
		}
	}
	if (!direct_access_)
	{
		if ((current_burst_ == mode_register.burst_length-1) &&
			(((rank_sel_ != rank_num-1) && (!bank_state[rank_sel_+1][bank_sel_].row_active)) || ((rank_sel_ == rank_num-1) && (!bank_state[0][(bank_sel_+1)%bank_num].row_active))))
			DQS = 'Z';
		else if (DQS == '0')
			DQS = '1';
		else
			DQS = '0';
	}

	return return_data;
}

const bool
SDRAM_DDR_device::SDRAM_write_command(unsigned		rank_sel_,
									  unsigned		bank_sel_,
									  SDRAM_addr_t	col_addr_,
									  bool			auto_precharge_)
{
	if (bank_state[rank_sel_][bank_sel_].row_active)
	{
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> write command accepted from activated bank." << endl;
#endif
		bank_state[rank_sel_][bank_sel_].col_index = col_addr_;
		bank_state[rank_sel_][bank_sel_].current_burst = 0;
		bank_state[rank_sel_][bank_sel_].auto_precharge = auto_precharge_;
		bank_state[rank_sel_][bank_sel_].write_recovery_count = mode_register.write_recovery;
	}
	else
	{
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> this row is not activated." << endl;
		sc_stop();
	}

	return true;
}

const bool
SDRAM_DDR_device::SDRAM_DDR_write_data(unsigned			rank_sel_,
									   unsigned			bank_sel_,
									   unsigned			current_burst_,
									   SDRAM_DDR_data_t	data_,
									   bool				direct_access_)
{
	if ((DQS != '0') && (DQS != '1'))
	{
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> DQS signal is not valid." << endl;
		sc_stop();
	}
	for (int i=0;i<component_per_rank_num;i++)
	{
		if (i<component_per_rank_num/2)
		{
			switch (ext_bitwidth_component)
			{
			case 8:
				row_buffer_byte[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+current_burst_] = ((byte)(data_.lower_bytes >> i*ext_bitwidth_component));
				break;
			case 16:
				row_buffer_halfword[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+current_burst_] = ((unsigned short)(data_.lower_bytes >> i*ext_bitwidth_component));
				break;
			case 32:
				row_buffer_word[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+current_burst_] = data_.lower_bytes;
				break;
			default:
				cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
				sc_stop();
			}
		}
		else
		{
			switch (ext_bitwidth_component)
			{
			case 8:
				row_buffer_byte[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+current_burst_] = ((byte)(data_.upper_bytes >> i*ext_bitwidth_component));
				break;
			case 16:
				row_buffer_halfword[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+current_burst_] = ((unsigned short)(data_.upper_bytes >> i*ext_bitwidth_component));
				break;
			case 32:
				row_buffer_word[rank_sel_][bank_sel_][i][bank_state[rank_sel_][bank_sel_].col_index+current_burst_] = data_.upper_bytes;
				break;
			default:
				cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
				sc_stop();	
			}
		}
	}
	if ((!direct_access_) && (current_burst_ == mode_register.burst_length-1) && (bank_state[rank_sel_][bank_sel_].auto_precharge))
	{
		write_finished[rank_sel_][bank_sel_] = true;
		write_finished_time[rank_sel_][bank_sel_] = sc_time_stamp();
		if (CLK == true)
		{
#ifdef	DEBUG_SDRAM_DDR
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> WR counter : " << bank_state[rank_sel_][bank_sel_].write_recovery_count;
#endif
			bank_state[rank_sel_][bank_sel_].write_recovery_count--;
#ifdef	DEBUG_SDRAM_DDR
			cout << " -> " << bank_state[rank_sel_][bank_sel_].write_recovery_count << endl;
#endif
		}
	}

	return true;
}

const bool
SDRAM_DDR_device::SDRAM_precharge(unsigned	rank_sel_,
								  unsigned	bank_sel_,
								  bool		precharge_all_)
{
	if (!precharge_all_)
	{
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Specific bank precharge is enabled." << endl;
#endif
		if (bank_state[rank_sel_][bank_sel_].row_active)
		{
			bank_state[rank_sel_][bank_sel_].precharge_enable = true;
			bank_state[rank_sel_][bank_sel_].precharge_enable_time = sc_time_stamp();
			bank_state[rank_sel_][bank_sel_].precharge_count = tRP;
#ifdef	DEBUG_SDRAM_DDR
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> precharge counter : " << bank_state[rank_sel_][bank_sel_].precharge_count;
#endif
			bank_state[rank_sel_][bank_sel_].precharge_count--;
#ifdef	DEBUG_SDRAM_DDR
			cout << " -> " << bank_state[rank_sel_][bank_sel_].precharge_count << endl;
#endif
		}
		else
		{
			cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> This bank is already precharged." << endl;
			sc_stop();
		}
	}
	else
	{
#ifdef	DEBUG_SDRAM_DDR
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> All the banks precharge is enabled." << endl;
#endif
		for (int i=0;i<rank_num;i++)
		{
			for (int j=0;j<bank_num;j++)
			{
				if (bank_state[i][j].row_active)
				{
					bank_state[i][j].precharge_enable = true;
					bank_state[i][j].precharge_enable_time = sc_time_stamp();
					bank_state[i][j].precharge_count = tRP;
#ifdef	DEBUG_SDRAM_DDR
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << rank_sel_ << ",BANK:" << bank_sel_ << ")> precharge counter : " << bank_state[i][j].precharge_count;
#endif
					bank_state[i][j].precharge_count--;
#ifdef	DEBUG_SDRAM_DDR
					cout << " -> " << bank_state[i][j].precharge_count << endl;
#endif
				}
				else
				{
#ifdef	DEBUG_SDRAM_DDR
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> precharge all doing nothing for idle banks." << endl;
#endif
				}
			}
		}
	}

	return true;
}

const sc_logic
SDRAM_DDR_device::SDRAM_DDR_get_DQS() const
{
	return DQS;
}

const bool
SDRAM_DDR_device::SDRAM_DDR_set_DQS(sc_logic	DQS_)
{
	DQS = DQS_;

	return true;
}

void
SDRAM_DDR_device::determine_nums(unsigned			tech_,
								 SDRAM_bitwidth_t	bitwidth_comp_)
{
	switch(tech_)
	{
	case 64:
		switch(bitwidth_comp_)
		{
		case 16:
			column_num = 256;
			row_num = 4096;
			bank_num = 4;
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM component bit width." << endl;
			sc_stop();
		}
		break;
	case 128:
		switch(bitwidth_comp_)
		{
		case 16:
			column_num = 512;
			row_num = 4096;
			bank_num = 4;
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM component bit width." << endl;
			sc_stop();
		}
		break;
	case 256:
		switch(bitwidth_comp_)
		{
		case 8:
			column_num = 1024;
			row_num = 8192;
			bank_num = 4;
			break;
		case 16:
			column_num = 512;
			row_num = 8192;
			bank_num = 4;
			break;
		case 32:
			column_num = 512;
			row_num = 4096;
			bank_num = 4;
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM component bit width." << endl;
			sc_stop();
		}
		break;
	case 512:
		switch(bitwidth_comp_)
		{
		case 8:
			column_num = 1024;
			row_num = 16384;
			bank_num = 4;
			break;
		case 16:
			column_num = 1024;
			row_num = 8192;
			bank_num = 4;
			break;
		case 32:
			column_num = 512;
			row_num = 8192;
			bank_num = 4;
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM component bit width." << endl;
			sc_stop();
		}
		break;
	case 1024:
		switch(bitwidth_comp_)
		{
		case 8:
			column_num = 1024;
			row_num = 16384;
			bank_num = 8;
			break;
		case 16:
			column_num = 1024;
			row_num = 8192;
			bank_num = 8;
			break;
		case 32:
			column_num = 1024;
			row_num = 8192;
			bank_num = 4;
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM component bit width." << endl;
			sc_stop();
		}
		break;
	case 2048:
		switch(bitwidth_comp_)
		{
		case 8:
			column_num = 1024;
			row_num = 32768;
			bank_num = 8;
			break;
		case 16:
			column_num = 1024;
			row_num = 16384;
			bank_num = 8;
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM component bit width." << endl;
			sc_stop();
		}
		break;
	case 4096:
		switch(bitwidth_comp_)
		{
		case 8:
			column_num = 1024;
			row_num = 65536;
			bank_num = 8;
			break;
		case 16:
			column_num = 1024;
			row_num = 32768;
			bank_num = 8;
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM component bit width." << endl;
			sc_stop();
		}
		break;
	default:
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Unsupported SDRAM technology." << endl;
		sc_stop();
	}
}

void
SDRAM_DDR_device::generate_cells()
{
	switch(ext_bitwidth_component)
	{
	case 8:
		SDRAM_array_byte = new byte****[rank_num];
		row_buffer_byte = new byte***[rank_num];
		output_buffer_byte = new byte***[component_per_rank_num];
		for (int i=0;i<rank_num;i++)
		{
			SDRAM_array_byte[i] = new byte***[bank_num];
			row_buffer_byte[i] = new byte**[bank_num];
			output_buffer_byte[i] = new byte**[component_per_rank_num];
			for (int j=0;j<bank_num;j++)
			{
				SDRAM_array_byte[i][j] = new byte**[component_per_rank_num];
				row_buffer_byte[i][j] = new byte*[component_per_rank_num];
				output_buffer_byte[i][j] = new byte*[component_per_rank_num];
				for (int k=0;k<component_per_rank_num;k++)
				{
					SDRAM_array_byte[i][j][k] = new byte*[row_num];
					output_buffer_byte[i][j][k] = new byte[DDR_MAX_BURST_LENGTH];
					for (int l=0;l<row_num;l++)
						SDRAM_array_byte[i][j][k][l] = new byte[column_num];
				}
			}
		}
		break;
	case 16:
		SDRAM_array_halfword = new unsigned short****[rank_num];
		row_buffer_halfword = new unsigned short***[rank_num];
		output_buffer_halfword = new unsigned short***[rank_num];
		for (int i=0;i<rank_num;i++)
		{
			SDRAM_array_halfword[i] = new unsigned short***[bank_num];
			row_buffer_halfword[i] = new unsigned short**[bank_num];
			output_buffer_halfword[i] = new unsigned short**[bank_num];
			for (int j=0;j<bank_num;j++)
			{
				SDRAM_array_halfword[i][j] = new unsigned short**[component_per_rank_num];
				row_buffer_halfword[i][j] = new unsigned short*[component_per_rank_num];
				output_buffer_halfword[i][j] = new unsigned short*[component_per_rank_num];
				for (int k=0;k<component_per_rank_num;k++)
				{
					SDRAM_array_halfword[i][j][k] = new unsigned short*[row_num];
					output_buffer_halfword[i][j][k] = new unsigned short[DDR_MAX_BURST_LENGTH];
					for (int l=0;l<row_num;l++)
						SDRAM_array_halfword[i][j][k][l] = new unsigned short[column_num];
				}
			}
		}
		break;
	case 32:
		SDRAM_array_word = new unsigned****[rank_num];
		row_buffer_word = new unsigned***[rank_num];
		output_buffer_word = new unsigned***[rank_num];
		for (int i=0;i<rank_num;i++)
		{
			SDRAM_array_word[i] = new unsigned***[bank_num];
			row_buffer_word[i] = new unsigned**[bank_num];
			output_buffer_word[i] = new unsigned**[bank_num];
			for (int j=0;j<bank_num;j++)
			{
				SDRAM_array_word[i][j] = new unsigned**[component_per_rank_num];
				row_buffer_word[i][j] = new unsigned*[component_per_rank_num];
				output_buffer_word[i][j] = new unsigned*[component_per_rank_num];
				for (int k=0;k<component_per_rank_num;k++)
				{
					SDRAM_array_word[i][j][k] = new unsigned*[row_num];
					output_buffer_word[i][j][k] = new unsigned[DDR_MAX_BURST_LENGTH];
					for (int l=0;l<row_num;l++)
						SDRAM_array_word[i][j][k][l] = new unsigned[column_num];
				}
			}
		}
		break;
	default:
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
		sc_stop();	
	}

	bank_state = new SDRAM_DDR_bank_state_t*[rank_num];
	for (int i=0;i<rank_num;i++)
	{
		bank_state[i] = new SDRAM_DDR_bank_state_t[bank_num];
		for (int j=0;j<bank_num;j++)
		{
			bank_state[i][j].row_active = false;
			bank_state[i][j].row_activate_enable = false;
			bank_state[i][j].read_precharge_commanded = false;
			bank_state[i][j].precharge_enable = false;
		}
	}

	read_commanded = new bool*[rank_num];
	read_commanded_time = new sc_time*[rank_num];
	write_finished = new bool*[rank_num];
	write_finished_time = new sc_time*[rank_num];
	for (int i=0;i<rank_num;i++)
	{
		read_commanded[i] = new bool[bank_num];
		read_commanded_time[i] = new sc_time[bank_num];
		write_finished[i] = new bool[bank_num];
		write_finished_time[i] = new sc_time[bank_num];
		for (int j=0;j<bank_num;j++)
		{
			read_commanded[i][j] = false;
			write_finished[i][j] = false;
		}
	}
}

void
SDRAM_DDR_device::initialize_cells()
{
	for (int i=0;i<rank_num;i++)
	{
		for (int j=0;j<bank_num;j++)
		{
			for (int k=0;k<component_per_rank_num;k++)
			{
				for (int l=0;l<row_num;l++)
				{
					for (int m=0;m<column_num;m++)
					{
						switch(ext_bitwidth_component)
						{
						case 8:
							SDRAM_array_byte[i][j][k][l][m] = 0xFF;
							break;
						case 16:
							SDRAM_array_halfword[i][j][k][l][m] = 0xFFFF;
							new unsigned short[column_num];
							break;
						case 32:
							SDRAM_array_word[i][j][k][l][m] = 0xFFFFFFFF;
							break;
						default:
							cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
							sc_stop();	
						}
					}
				}
			}
		}
	}
}

void
SDRAM_DDR_device::bank_count_action()
{
	while (true)
	{
		for (int i=0;i<rank_num;i++)
		{
			for (int j=0;j<bank_num;j++)
			{
				if ((bank_state[i][j].row_activate_enable) && (bank_state[i][j].row_activate_enable_time != sc_time_stamp()))
				{
					if (bank_state[i][j].row_activate_count != 0)
					{
#ifdef	DEBUG_SDRAM_DDR
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << i << ",BANK:" << j << ")> row activate counter : " << bank_state[i][j].row_activate_count;
#endif
						bank_state[i][j].row_activate_count--;
#ifdef	DEBUG_SDRAM_DDR
						cout << " -> " << bank_state[i][j].row_activate_count << endl;
#endif
					}
					else
					{
#ifdef	DEBUG_SDRAM_DDR
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << i << ",BANK:" << j << ")> row activate counter became 0" << endl;
#endif
						bank_state[i][j].row_active = true;
						bank_state[i][j].row_activate_enable = false;
						for (int k=0;k<component_per_rank_num;k++)
						{
							switch (ext_bitwidth_component)
							{
							case 8:
								row_buffer_byte[i][j][k] = new byte[column_num];
								for (int l=0;l<column_num;l++)
								{
									row_buffer_byte[i][j][k][l] = SDRAM_array_byte[i][j][k][bank_state[i][j].row_index][l];
									SDRAM_array_byte[i][j][k][bank_state[i][j].row_index][l] = 0xCD;
								}
								break;
							case 16:
								row_buffer_halfword[i][j][k] = new unsigned short[column_num];
								for (int l=0;l<column_num;l++)
								{
									row_buffer_halfword[i][j][k][l] = SDRAM_array_halfword[i][j][k][bank_state[i][j].row_index][l];
									SDRAM_array_halfword[i][j][k][bank_state[i][j].row_index][l] = 0xCDCD;
								}
								break;
							case 32:
								row_buffer_word[i][j][k] = new unsigned[column_num];
								for (int l=0;l<column_num;l++)
								{
									row_buffer_word[i][j][k][l] = SDRAM_array_word[i][j][k][bank_state[i][j].row_index][l];
									SDRAM_array_word[i][j][k][bank_state[i][j].row_index][l] = 0xCDCDCDCD;
								}
								break;
							default:
								cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
								sc_stop();
							}
						}
					}
				}
				else if ((bank_state[i][j].precharge_enable) && (bank_state[i][j].precharge_enable_time != sc_time_stamp()))
				{
					if (bank_state[i][j].precharge_count != 0)
					{
#ifdef	DEBUG_SDRAM_DDR
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << i << ",BANK:" << j << ")> precharge counter : " << bank_state[i][j].precharge_count;
#endif
						bank_state[i][j].precharge_count--;
#ifdef	DEBUG_SDRAM_DDR
						cout << " -> " << bank_state[i][j].precharge_count << endl;
#endif
					}
					else
					{
#ifdef	DEBUG_SDRAM_DDR
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << i << ",BANK:" << j << ")> precharge counter became 0" << endl;
#endif
						bank_state[i][j].row_active = false;
						bank_state[i][j].precharge_enable = false;
						for (int k=0;k<component_per_rank_num;k++)
						{
							switch (ext_bitwidth_component)
							{
							case 8:
								for (int l=0;l<column_num;l++)
									SDRAM_array_byte[i][j][k][bank_state[i][j].row_index][l] = row_buffer_byte[i][j][k][l];
								delete[] row_buffer_byte[i][j][k];
								break;
							case 16:
								for (int l=0;l<column_num;l++)
									SDRAM_array_halfword[i][j][k][bank_state[i][j].row_index][l] = row_buffer_halfword[i][j][k][l];
								delete[] row_buffer_halfword[i][j][k];
								break;
							case 32:
								for (int l=0;l<column_num;l++)
									SDRAM_array_word[i][j][k][bank_state[i][j].row_index][l] = row_buffer_word[i][j][k][l];
								delete[] row_buffer_word[i][j][k];
								break;
							default:
									cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
								sc_stop();
							}
						}
					}
				}
			}
		}
		wait();
	}
}

void
SDRAM_DDR_device::command_count_action()
{
	while (true)
	{
		for (int i=0;i<rank_num;i++)
		{
			for (int j=0;j<bank_num;j++)
			{
				if ((read_commanded[i][j]) && (read_commanded_time[i][j] != sc_time_stamp()))
				{
					if (bank_state[i][j].current_burst < mode_register.burst_length)
					{
						for (int k=0;k<component_per_rank_num;k++)
						{
							switch (ext_bitwidth_component)
							{
							case 8:
								output_buffer_byte[i][j][k][bank_state[i][j].current_burst] = row_buffer_byte[i][j][k][bank_state[i][j].col_index+bank_state[i][j].current_burst];
								break;
							case 16:
								output_buffer_halfword[i][j][k][bank_state[i][j].current_burst] = row_buffer_halfword[i][j][k][bank_state[i][j].col_index+bank_state[i][j].current_burst];
								break;
							case 32:
								output_buffer_word[i][j][k][bank_state[i][j].current_burst] = row_buffer_word[i][j][k][bank_state[i][j].col_index+bank_state[i][j].current_burst];
								break;
							default:
								cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> wrong external bit width." << endl;
								sc_stop();	
							}
						}
#ifdef	DEBUG_SDRAM_DDR
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << i << ",BANK:" << j << ")> current burst : " << bank_state[i][j].current_burst;
#endif
						bank_state[i][j].current_burst++;
#ifdef	DEBUG_SDRAM_DDR
						cout << " -> " << bank_state[i][j].current_burst << endl;
#endif
					}
					else if ((!bank_state[i][j].read_precharge_commanded) && (CLK == true) && (bank_state[i][j].auto_precharge))
					{
						SDRAM_precharge(i, j, false);
						bank_state[i][j].read_precharge_commanded = true;
					}
					if (CLK == true)
					{
#ifdef	DEBUG_SDRAM_DDR
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << i << ",BANK:" << j << ")> CAS latency : " << bank_state[i][j].CAS_latency_count;
#endif
						bank_state[i][j].CAS_latency_count--;
#ifdef	DEBUG_SDRAM_DDR
						cout << " -> " << bank_state[i][j].CAS_latency_count << endl;
#endif
						if (bank_state[i][j].CAS_latency_count == 0)
						{
							read_commanded[i][j] = false;
							bank_state[i][j].read_precharge_commanded = false;
						}
						else if ((bank_state[i][j].CAS_latency_count == 1) && (DQS == 'Z'))
						{
							DQS = '0';
						}
					}
				}
				if ((write_finished[i][j]) && (write_finished_time[i][j] != sc_time_stamp()))
				{
					if (bank_state[i][j].write_recovery_count != 0)
					{
						if (CLK == true)
						{
#ifdef	DEBUG_SDRAM_DDR
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "(RANK:" << i << ",BANK:" << j << ")> WR counter : " << bank_state[i][j].write_recovery_count;
#endif
							bank_state[i][j].write_recovery_count--;
#ifdef	DEBUG_SDRAM_DDR
							cout << " -> " << bank_state[i][j].write_recovery_count << endl;
#endif
						}
					}
					else
					{
						if (CLK == true)
						{
							if (bank_state[i][j].auto_precharge)
							{
								write_finished[i][j] = false;
								SDRAM_precharge(i, j, false);
							}
						}
					}
				}
			}
		}
		wait();
	}
}